package code17_reflect;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;

public class TestMethod {

	public static void main(String[] args) throws Exception {
		f1();
		
		//f2();
	}

	private static void f2() throws Exception {
		Class<?> c = Stu.class;
		try {
			// 创建对象, 方便执行对象的指定方法
			Object obj = c.newInstance();
			
			Method m = c.getDeclaredMethod("talk", String.class);
			
			// 访问受限制时, 可以设置 允许访问, 这样就可以正常访问方法
			m.setAccessible(true);
			
			// 如果访问的方法是 静态的, 则不需要传入对象, 传入 null
			// 执行方法
			// 正常操作: 接收返回值 = 对象.方法(参数值);
			// 反射操作: 使用指定对象来执行该方法, 并传入该方法需要的参数值
			// 如果方法有返回值, 则 invoke 返回对应的值, 否则 invoke 返回 null
			Object returnValue = m.invoke(obj, "hello world");
			System.out.println("returnValue:" + returnValue);
		} catch (IllegalArgumentException e) {
			// 参数错误
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// 使用的对象有问题
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// 访问受限制, 例如 private
			e.printStackTrace();
		}
	}

	private static void f1() {
		Class<?> c = Stu.class;
		// 1. 获取 当前类 以及 其超类 中所有 public 修饰的方法
		Method[] methods = c.getMethods();
		// 2. 获取 当前类中 所有方法 (含 private)
//		methods = c.getDeclaredMethods();
		for (Method m : methods) {
			// 修饰符、返回值类型、方法名、参数列表、抛出的异常
			String modifiers = Modifier.toString(m.getModifiers());
			Class<?> returnType = m.getReturnType();
			String name = m.getName();
			//Parameter[] parameters = m.getParameters();
			Class<?>[] parameterTypes = m.getParameterTypes();
			Class<?>[] exceptionTypes = m.getExceptionTypes();
			System.out.println(
					modifiers + " "
					+ returnType.getSimpleName() + " "
					+ name + "("
					+ Arrays.toString(parameterTypes) + ") "
					+ "throws " + Arrays.toString(exceptionTypes) + " { }"
					);
		}
		System.out.println("===============");
		try {
			// 3.根据方法名,方法的参数列表 获取 当前类 以及 其超类 中对应的  public 修饰的方法(重写的方法, 只能获取到自己的)
			// 参数列表是 参数的类型, 参数类型的顺序
			// 没有参数的方法, 不用传入参数类型
			Method m = c.getMethod("study", String.class, int.class);
			System.out.println("study:" + m);
		} catch (NoSuchMethodException e) {
			// 没有对应的方法
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		}
		
		try {
			// 4. 根据方法名,方法的参数列表 获取 当前类中 指定方法 (含 private)
			Method m = c.getDeclaredMethod("talk", String.class);
			System.out.println("talk:" + m);
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		}
		
	}
	
}
